package viz_ui;

import java.awt.Color;
import java.util.HashMap;

import buttons.Button;
import buttons.TextButton;
import buttons.control.C_Button;
import buttons.control.C_DoubleSlider;
import buttons.control.C_VerticalDoubleSlider;

import controllers.ControlManager;

import processing.core.PApplet;
import utilities.EventListener;
import utilities.EventOwner;
import view.DisplayList;
import view.V_DisplayObject;
import viz_main.ScatterPlotAxis;
import viz_main.VizApplet;

// NOTE: Allow support for re-arranging each axis
// NOTE2: to determine if a line should be brushed, check the current axis and the next axis. If both fall under the filter then brush
// 		  otherwise don't brush at all.

public class ParallelView extends V_DisplayObject implements EventListener {
	
	private VizApplet parent;
	private ParallelAxis[] interactiveAxisList;
	private TextButton[] swapButtonList; // buttons used to swap the position of 2 adjacent ParallelAxis
	private ParallelLine[] lineList;
	private float lineHeight;
	private int curSelectedIndex = -1;
	
	public ParallelView(float x, float y, float w, float h, VizApplet p)
	{
		swapButtonList = new TextButton[4];
		this.init(x, y, w, h, new Color(230, 230, 230, 150));
		parent = p;
		lineHeight = ySize - 70;
	}
	
	// load data into the visual representation for each axis. (An array of ParallelAxis objects)
	// ParallelAxis manages interaction with and display of each axis.
	public void initAxis(HashMap axisList, DisplayList v, ControlManager c)
	{
		lineList = new ParallelLine[parent.totalRecords];
		for(int i = 0; i < lineList.length; i++)
		{ // create all the lines and assign them an array length of the number of columns in this dataset
			lineList[i] = new ParallelLine(parent.labels.length);
		}
		
		interactiveAxisList = new ParallelAxis[parent.labels.length];
	    boolean addButton = true;
	    int buttonIndex = 0;
		for(int i = 0; i < parent.labels.length; i++)
		{
			float spacing = 40 + (((xSize)/parent.labels.length)*i);
			ScatterPlotAxis tmpAxis = (ScatterPlotAxis) axisList.get(parent.labels[i]);
			tmpAxis.fitToBounds();
			interactiveAxisList[i] = new ParallelAxis(v, c, parent.labels[i], 10.0f, lineHeight, parent, this);
			interactiveAxisList[i].setLocation(xLoc+spacing, yLoc+30);
			interactiveAxisList[i].setAxis(tmpAxis);
			interactiveAxisList[i].setBID(i+""); // assign the index to this ID
			interactiveAxisList[i].addSubscriber(this);
			if(addButton == true)
			{
				addButton = false;
				swapButtonList[buttonIndex] = new TextButton(v, c, "> <", 25, 12, xLoc+spacing+40, yLoc+ySize-20, parent);
				swapButtonList[buttonIndex].addSubscriber(this);
				int next = i+1;
				swapButtonList[buttonIndex].setBID(buttonIndex+","+i+","+next); // use the BID to refer to the axis on either side of this button
				buttonIndex++;
			}
			if (i+2 < parent.labels.length){
				addButton = true;
			}
			
			// add all datacases to each line on this axis:
			float xPosition_1 = interactiveAxisList[i].getView().getXLoc();
    		float yPosition_1 = interactiveAxisList[i].getView().getYLoc();
    		float yStart_1 = yPosition_1 + lineHeight;
    		float min_1 = interactiveAxisList[i].getAxis().getMin();
    		float max_1 = interactiveAxisList[i].getAxis().getMax();			
			for(int j = 0; j < lineList.length; j++)
			{ // create all the lines and assign them an array length of the number of columns in this dataset
				float value_1 = interactiveAxisList[i].getAxis().getElement(j);
	    		float yPercent_1 = (value_1 - min_1)/(max_1 - min_1);
	    		float localY_1 = ((yStart_1 - yPosition_1)*Math.max(0.0f, Math.min(yPercent_1, 1.0f) ));
				
				lineList[j].addElement(i, xPosition_1, yStart_1 - localY_1, yPercent_1);
			}
		}
	}
	
	@Override
	public void display(PApplet p)
	{
		p.noStroke();
	    p.fill(bgColor);
	    p.rect(xLoc, yLoc, xSize, ySize);
	    
	    for(int i = 0; i < swapButtonList.length; i++)
		{
	    	swapButtonList[i].display(p);
		}
	    
	    for(int i = 0; i < lineList.length; i++)
	    {
	    	lineList[i].display(p);
	    }
	    if(curSelectedIndex > -1)
	    {
	    	lineList[curSelectedIndex].display(p); // draw the selected line again
	    }
	    
	    for(int i = 0; i < interactiveAxisList.length; i++)
		{
	    	interactiveAxisList[i].display(p);
		}
	}

	public void handleEvent(String trigger, EventOwner obj) {
		if(trigger.equals("toggleOn") || trigger.equals("toggleOff")) {
			for(int j = 0; j < lineList.length; j++)
			{
				lineList[j].setGrayedOut( lineList[j].checkRange(interactiveAxisList, 1, 1, true) );
			}
		}
		
		// Handle axis swapping:
		if(trigger.equals("buttonPressed"))
		{
			C_Button tmpButton = (C_Button)obj;
			String[] curIndexes = tmpButton.getBID().split(",");
			int bIndex = Integer.parseInt(curIndexes[0]);
			int leftIndex = Integer.parseInt(curIndexes[1]);
			int rightIndex = Integer.parseInt(curIndexes[2]);
			
			float leftX = interactiveAxisList[leftIndex].getView().getXLoc();
			float rightX = interactiveAxisList[rightIndex].getView().getXLoc();
			
			interactiveAxisList[leftIndex].setXLocation(rightX);
			interactiveAxisList[leftIndex].setBID(rightIndex+"");
			interactiveAxisList[rightIndex].setXLocation(leftX);
			interactiveAxisList[rightIndex].setBID(leftIndex+"");
			
			for(int j = 0; j < lineList.length; j++)
			{
				lineList[j].setGrayedOut( lineList[j].checkRange(interactiveAxisList, 1, 1, true) );
			}
			
			for(int j = 0; j < lineList.length; j++)
			{
				lineList[j].swap(bIndex, bIndex+1, leftX, rightX);
			}
			
			tmpButton.setBID(bIndex+","+rightIndex+","+leftIndex); // adjust the index values of the button
			// adjust the index values of adjacent buttons:
			if(bIndex == 0)
			{
				C_Button tmpButton_Right = swapButtonList[bIndex+1].getController();;
				String[] rightIndexes = tmpButton_Right.getBID().split(",");
				tmpButton_Right.setBID(rightIndexes[0]+","+leftIndex+","+rightIndexes[2]);
				
			}
			else if(bIndex == swapButtonList.length-1)
			{
				C_Button tmpButton_Left = swapButtonList[bIndex-1].getController();;
				String[] leftIndexes = tmpButton_Left.getBID().split(",");
				tmpButton_Left.setBID(leftIndexes[0]+","+leftIndexes[1]+","+rightIndex);
			}
			else 
			{
				C_Button tmpButton_Right = swapButtonList[bIndex+1].getController();;
				String[] rightIndexes = tmpButton_Right.getBID().split(",");
				tmpButton_Right.setBID(rightIndexes[0]+","+leftIndex+","+rightIndexes[2]);
				
				C_Button tmpButton_Left = swapButtonList[bIndex-1].getController();;
				String[] leftIndexes = tmpButton_Left.getBID().split(",");
				tmpButton_Left.setBID(leftIndexes[0]+","+leftIndexes[1]+","+rightIndex);
			}
		}
		// Handle per-axis filtering:
		else if(obj.getClass().getName().equals(C_VerticalDoubleSlider.class.getName()))
		{
			C_VerticalDoubleSlider tmpSlider = (C_VerticalDoubleSlider)obj;
			int sliderIndex = Integer.parseInt(tmpSlider.getBID());
			// filter that axis based on slider position:
			for(int j = 0; j < lineList.length; j++)
			{
				lineList[j].setGrayedOut( lineList[j].checkRange(interactiveAxisList, sliderIndex, sliderIndex, true) );
			}
		}
	}
	
	// Select or De-Select a single Line:
	public void selectLine(int index)
	{
		if(curSelectedIndex > -1) // deselect previous line if there was one
		{
			lineList[curSelectedIndex].setSelected(false);
		}
		lineList[index].setSelected(true);
		curSelectedIndex = index;
	}
	
	public void deselectCurrentLine()
	{
		if (curSelectedIndex > -1) {
			lineList[curSelectedIndex].setSelected(false);
			curSelectedIndex = -1;
		}
	}
	
	public int getSelectedIndex()
	{
		return curSelectedIndex;
	}

}
